﻿using CleanArchitecture.Core;
using CleanArchitecture.Core.Configuration;
using CleanArchitecture.Core.Handlers;
using CleanArchitecture.Core.Helper;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Core.Interfaces.Cache;
using CleanArchitecture.Infrastructure.AutoMapper;
using CleanArchitecture.Infrastructure.Configuration;
using CleanArchitecture.Infrastructure.Entities;
using CleanArchitecture.Infrastructure.Entities.AdminUsers;
using CleanArchitecture.Infrastructure.Entities.Business;
using CleanArchitecture.Infrastructure.Entities.Settings;
using CleanArchitecture.Infrastructure.Interfaces;
using CleanArchitecture.Infrastructure.Interfaces.AdminUsers;
using CleanArchitecture.Infrastructure.Interfaces.Common;
using CleanArchitecture.Infrastructure.Interfaces.Media;
using CleanArchitecture.Infrastructure.Interfaces.Security;
using CleanArchitecture.Infrastructure.Interfaces.SystemManage;
using CleanArchitecture.Infrastructure.Models;
using CleanArchitecture.Infrastructure.Models.AdminUsers;
using CleanArchitecture.Web.Backend.BackendApi;
using CleanArchitecture.Web.Factories;
using CleanArchitecture.Web.Validators;
using CleanArchitecture.Web.Validators.AdminUsers;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace CleanArchitecture.Web.Controllers.Backend.BackendApi
{
    /// <summary>
    /// DavidLee 2019/12/27 通过继承父类Controller将Api调用与Controller渲染
    /// 前端页面分离，保持页面渲染简洁性
    /// 前端页面渲染控制器路由可在RouteProvider中注册，Api Ajax路由由Route Attribute注册
    /// </summary>
    public class BackendAdminUserApiController : BackendAdminUserController
    {
        private readonly IAdminUserService _adminuserService;
        private readonly IAdminUserRegistrationService _adminuserRegistrationService;
        private readonly IAdminUserModelFactory _adminusermodelFactory;
        private readonly IPermissionService _permissionService;
        private readonly AdminUserSettings _adminuserSettings;
        private readonly IWorkContext _workContext;
        private readonly IWebHelper _webHelper;
        private readonly ISystemDataDicService _systemdatadicService;
        private readonly IStaticCacheManager _cacheManager;
        private readonly IFileUploadService _fileuploadService;
        private readonly IGenericAttributeService _gaattributeService;

        public BackendAdminUserApiController(IAdminUserService adminuserService,
            IAdminUserRegistrationService adminuserRegistrationService,
            IAdminUserModelFactory adminusermodelFactory,
            AdminUserSettings adminuserSettings,
            IWorkContext workContext,
            IPermissionService permissionService,
            ISystemModuleService systemmoduleService,
            IWebHelper webHelper,
            ISystemDataDicService systemdatadicService,
            IStaticCacheManager cacheManager,
            IFileUploadService fileuploadService,
            IGenericAttributeService gaattributeService)
            :base(adminusermodelFactory,
                 adminuserSettings,
                 workContext,
                 permissionService,
                 systemmoduleService)
        {
            _adminuserService = adminuserService;
            _adminuserRegistrationService = adminuserRegistrationService;
            _adminusermodelFactory = adminusermodelFactory;
            _permissionService = permissionService;
            _adminuserSettings = adminuserSettings;
            _workContext = workContext;
            _webHelper = webHelper;
            _systemdatadicService = systemdatadicService;
            _cacheManager = cacheManager;
            _fileuploadService = fileuploadService;
            _gaattributeService = gaattributeService;
        }

        [HttpPost(BackendApiRouteConfig.UploadAdminUserAvatar)]
        public async Task<IActionResult> UploadAdminUserAvatar([FromForm]ImageUploadForm imagedata)
        {
            try
            {
                if (imagedata == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (imagedata.ImageForm == null) throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
                var account = _adminuserService.GetAdminUserById(imagedata.Id);
                FileUpload picture = null;
                var retunData = string.Empty;
                if (account == null) throw new NowaException(ApiResponseMessages.AdminUserNotExsitsError);
                else if (account.IsActive == EntityEnumConfig.LockState.InActive) throw new NowaException(ApiResponseMessages.AdminUserNotExsitsError);
                else
                {//update image
                    //imageUrl 格式为'FileUploadId;ImageUrl' 如"1;/uploaded/Image/20200211/logo.png"
                    //保存FileUpload存储的图片Id 和 图片存储路径
                    //图片Id用于删除原有图片数据
                    //Url用于前端快速显示图片 而不用通过图片id再去查图片路径
                    //只有更改图片时才删除原有图片
                    var oldImageData = imagedata.ImageUrl.Split(';').ToArray();
                    if (oldImageData.Length != 2) throw new NowaException(string.Format(ApiResponseMessages.BugReport, "ImageUrl Not Correct"));
                    picture = _fileuploadService.GetFileUploadEntityById(int.Parse(oldImageData[0]));
                    if (picture == null)
                    {
                        picture = _fileuploadService.InsertFileEntity(imagedata.ImageForm, nameof(UploadUseCategory.FaceImage));
                        retunData = picture.Id.ToString() + ";";
                        retunData += _fileuploadService.GetFileUrl(picture);
                    }
                    else
                    {
                        oldImageData[1] = picture.SeoFilename;
                        var fileProvider = EngineContext.Current.Resolve<INowaFileProvider>();
                        picture.FileBinary = new FileBinary
                        {
                            FKFileUploadId = picture.Id,
                            BinaryData = GetFileBits(imagedata.ImageForm)
                        };
                        picture.SeoFilename = _fileuploadService.GetFileSeName(fileProvider.GetFileNameWithoutExtension(imagedata.ImageForm.FileName));
                        picture.FileType = FileType.Image;
                        picture.StoreType = EntityEnumConfig.FileStoreType.LocalStorage;
                        picture.TitleAttribute = account.UserName;
                        picture.AltAttribute = account.UserName;
                        picture.IsNew = EntityEnumConfig.YesorNo.YES;
                        picture.MimeType = imagedata.ImageForm.ContentType;
                        picture.Category = nameof(UploadUseCategory.FaceImage);
                        picture.UpdatedOnTimeUtc = DateTime.UtcNow;
                        if (string.IsNullOrEmpty(picture.MimeType))
                            picture.MimeType = MimeTypes.GetSupportFileMimetypeByFileExt(fileProvider.GetFileExtension(imagedata.ImageForm.FileName));

                        picture = _fileuploadService.UpdateFileEntityWithBinary(picture, oldImageData[1]);
                        retunData = picture.Id.ToString() + ";";
                        retunData += _fileuploadService.GetFileUrl(picture);
                    }

                    //设置头像链接到account
                    _gaattributeService.SaveAttribute<string>(account, "FaceImageUrl", retunData);
                    return SuccessJson(ApiResponseMessages.AvatarUploadSuccess, retunData);
                }
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 个人中心-账号设置
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost(BackendApiRouteConfig.UpdateCurrentAdminUserAccountInfo)]
        public async Task<IActionResult> UpdateCurrentAdminUserAccount([FromBody]AdminUserModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    var userEntity = _adminuserService.GetAdminUserById(model.Id);
                    if (userEntity == null)
                        throw new NowaException(ApiResponseMessages.AdminUserNotExsitsError);
                    if (!string.IsNullOrEmpty(model.UserName))
                    {
                        userEntity.UserName = model.UserName;
                        _adminuserService.UpdateAdminUser(userEntity);
                        return SuccessJson(ApiResponseMessages.AccountSettingSuccess);
                    }
                    if (!string.IsNullOrEmpty(model.NewPassword) && !string.IsNullOrEmpty(model.OldPassword))
                    {
                        if (!_adminuserRegistrationService.ChangePassword(userEntity.Id, CommonHelper.To<int>(model.PasswordStrongLevel), model.OldPassword, model.NewPassword))
                            throw new NowaException(ApiResponseMessages.ErrorPasswordForChange);
                        return SuccessJson(ApiResponseMessages.AccountSettingSuccessReLogin);
                    }
                }
                catch(NowaException nex)
                {
                    return ErrorJson(nex.Message);
                }
                catch(Exception ex)
                {
                    return ErrorJson(ex.Message);
                }
            }
            return ErrorJson(ApiResponseMessages.ModelBindingError);
        }

        [Route(BackendApiRouteConfig.LoadAdminRoles)]
        public async Task<IActionResult> LoadAdminRoles()
        {
            try
            {
                //var roleModels = _adminusermodelFactory.PrepareAdminRoleModels();
                var roleModels = _adminuserService.GetAdminRoleModelsAll();
                return SuccessJson("", roleModels);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpPost(BackendApiRouteConfig.LoadAdminUsers)]
        public async Task<IActionResult> LoadAdminUsers([FromBody]AdminUserSearchModel searchModel)
        {
            try
            {
                var adminuserModels = _adminusermodelFactory.PrepareAdminUserListModel(searchModel);
                return SuccessJson("", adminuserModels);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 用户管理模块，新建(注册)/修改用户
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost(BackendApiRouteConfig.UpdateAdminUserAccountInfo)]
        public async Task<IActionResult> UpdateAdminUserAccount([FromBody] AdminUserModel model)
        {
            var modelValidateMsg = ModelState.GetValidationSummary();
            if (modelValidateMsg == null)
            {
                try
                {
                    if (model.Id == 0)
                    {//新用户注册
                        NewAdminUserRegister(model);
                        return SuccessJson(ApiResponseMessages.NewRegisterAccountSuccess);
                    }
                    else
                    {//用户信息修改
                        AdminUserManageUpdate(model);
                        return SuccessJson(ApiResponseMessages.AccountSettingSuccessConfirm);
                    }
                }
                catch (NowaException nex)
                {
                    return ErrorJson(nex.Message);
                }
                catch (Exception ex)
                {
                    return ErrorJson(ex.Message);
                }
            }
            return ErrorJson(modelValidateMsg);
        }
        private void NewAdminUserRegister(AdminUserModel model)
        {
            //DavidLee 2020/10/15
            //发现ModelValidator新用法，结合使用ModelState.IsValid可在数据模型赋值时即可检测数据是否符合校验规则
            //AccountValidator validator = new AccountValidator(_adminuserSettings);
            //var results = validator.Validate(model);
            //if (!results.IsValid)
            //{
            //    foreach (var failure in results.Errors)
            //    {
            //        throw new NowaException(failure.ErrorMessage);
            //    }
            //}
            if (model.IsActive == EntityEnumConfig.LockState.InActive)
                throw new NowaException(ApiResponseMessages.NewRegisterAccountNotActive);
            if (string.IsNullOrEmpty(model.NewPassword))
                throw new NowaException(ApiResponseMessages.NewRegisterAccountPasswordNotNull);
            if (model.SelectedRoleIds.Count == 0)
                throw new NowaException(ApiResponseMessages.AccountNotAssignRoleError);
            AdminUser checkUnique;
            checkUnique = _adminuserService.GetAdminUserByLoginname(model.UserLoginName);
            if (checkUnique != null)
                throw new NowaException(string.Format(ApiResponseMessages.AccountNotUniqueError, model.UserLoginName));
            checkUnique = _adminuserService.GetAdminUserByEmail(model.Email);
            if (checkUnique != null)
                throw new NowaException(string.Format(ApiResponseMessages.AccountNotUniqueError, model.Email));
            checkUnique = _adminuserService.GetAdminUserByMobile(model.Mobile);
            if (checkUnique != null)
                throw new NowaException(string.Format(ApiResponseMessages.AccountNotUniqueError, model.Mobile));

            var userEntity = model.ToEntity<AdminUser>();
            userEntity.FailedLoginAttempts = 0;
            userEntity.LastLoginIp = _webHelper.GetCurrentIpAddress();
            userEntity.LastLoginTimeUtc = userEntity.CreatedOnTimeUtc = DateTime.UtcNow;
            userEntity.IsActive = EntityEnumConfig.LockState.Active;
            userEntity.IsDeleted = EntityEnumConfig.DeleteState.Active;

            foreach (var roleid in model.SelectedRoleIds)
            {
                userEntity.AdminuserAdminroleMappings.Add(new AdminUserAdminRoleMapping { FKAdminRoleId = roleid });
            }
            userEntity.SysLogLvl = SystemLogLevel.Information;
            userEntity.SysLogMsg = "新用户注册：账号：" + userEntity.UserLoginName + " 操作人：" + _workContext.CurrentAdminUser.UserName;
            _adminuserService.InsertAdminUser(userEntity);
            if (!_adminuserRegistrationService.ChangePassword(userEntity.Id, CommonHelper.To<int>(model.PasswordStrongLevel), string.Empty, model.NewPassword, SkipOldPasswordCheck: true))
                throw new NowaException(ApiResponseMessages.ErrorPasswordForChange);
        }

        private void AdminUserManageUpdate(AdminUserModel model)
        {
            var userEntity = _adminuserService.GetAdminUserById(model.Id);
            if (userEntity == null)
                throw new NowaException(ApiResponseMessages.AdminUserNotExsitsError);
            AdminUser checkUnique;
            AccountValidator validator = new AccountValidator(_adminuserSettings);
            if (model.UserLoginName != userEntity.UserLoginName)
            {
                checkUnique = _adminuserService.GetAdminUserByLoginname(model.UserLoginName);
                if (checkUnique != null && checkUnique.Id != userEntity.Id)
                    throw new NowaException(string.Format(ApiResponseMessages.AccountNotUniqueError, model.UserLoginName));
                userEntity.UserLoginName = model.UserLoginName;
            }
            if (model.Email != userEntity.Email)
            {
                checkUnique = _adminuserService.GetAdminUserByEmail(model.Email);
                if (checkUnique != null && checkUnique.Id != userEntity.Id)
                    throw new NowaException(string.Format(ApiResponseMessages.AccountNotUniqueError, model.Email));
                userEntity.Email = model.Email;
            }
            if (model.Mobile != userEntity.Mobile)
            {
                checkUnique = _adminuserService.GetAdminUserByMobile(model.Mobile);
                if (checkUnique != null && checkUnique.Id != userEntity.Id)
                    throw new NowaException(string.Format(ApiResponseMessages.AccountNotUniqueError, model.Mobile));
                userEntity.Mobile = model.Mobile;
            }
            var results = validator.Validate(model);
            if (!results.IsValid)
            {
                foreach (var failure in results.Errors)
                {
                    throw new NowaException(failure.ErrorMessage);
                }
            }
            if (!string.IsNullOrEmpty(model.UserName))
                userEntity.UserName = model.UserName;
            if (model.IsActive == EntityEnumConfig.LockState.Active)
            {
                userEntity.IsActive = EntityEnumConfig.LockState.Active;
                userEntity.FailedLoginAttempts = 0;
            }
            if (!string.IsNullOrEmpty(model.NewPassword))
            {
                if (!_adminuserRegistrationService.ChangePassword(userEntity.Id, CommonHelper.To<int>(model.PasswordStrongLevel), string.Empty, model.NewPassword, SkipOldPasswordCheck: true))
                    throw new NowaException(ApiResponseMessages.ErrorPasswordForChange);
            }
            if (model.SelectedRoleIds.Count == 0) //借用RoleNames字段存储用户分配角色ID
                throw new NowaException(ApiResponseMessages.AccountNotAssignRoleError);
            else
            {
                userEntity.AdminuserAdminroleMappings.Clear();
                foreach(int roleid in model.SelectedRoleIds)
                {
                    userEntity.AdminuserAdminroleMappings.Add(new AdminUserAdminRoleMapping { FKAdminUserId = userEntity.Id, FKAdminRoleId = roleid });
                }
            }
            _adminuserService.UpdateAdminUser(userEntity);
            string cacheKey = string.Format(DefaultCacheConfig.AdminUserIsAdmin, userEntity.Id);
            _cacheManager.Remove(cacheKey);
        }

        [HttpDelete(BackendApiRouteConfig.DeleteAdminUserAccount)]
        public async Task<IActionResult> DeleteAdminUserAccount([FromBody]DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                var deleteNode = _adminuserService.GetAdminUserById(node.EntityId);
                if (deleteNode == null || deleteNode.IsDeleted == EntityEnumConfig.DeleteState.Deleted)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);
                if (deleteNode.Id == _workContext.CurrentAdminUser.Id)
                    throw new NowaException(ApiResponseMessages.CannotDeleteSelfAccount);
                deleteNode.UserLoginName = deleteNode.UserLoginName + "-Deleted";
                deleteNode.Email = deleteNode.Email + "-Deleted";
                deleteNode.Mobile = deleteNode.Mobile + "-Deleted";
                deleteNode.IsActive = EntityEnumConfig.LockState.InActive;
                deleteNode.IsDeleted = EntityEnumConfig.DeleteState.Deleted;
                deleteNode.SysLogLvl = Core.Configuration.SystemLogLevel.Information;
                deleteNode.SysLogMsg = string.Format("用户Id：{0}被删除，操作人：{1}", deleteNode.Id, _workContext.CurrentAdminUser.UserName);
                _adminuserService.UpdateAdminUser(deleteNode);
                
                return SuccessJson(ApiResponseMessages.UpdateSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 用户角色管理模块，新建/修改用户角色
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost(BackendApiRouteConfig.UpdateAdminRole)]
        public async Task<IActionResult> UpdateAdminRole([FromBody]AdminRoleModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    if (model.Id == 0) //新增用户角色
                        CreateAdminRole(model);
                    else               //用户角色修改
                        AdminRoleManageUpdate(model);

                    return SuccessJson(ApiResponseMessages.UpdateSuccessAndRefreshCache);
                }
                catch (NowaException nex)
                {
                    return ErrorJson(nex.Message);
                }
                catch (Exception ex)
                {
                    return ErrorJson(ex.Message);
                }
            }
            return ErrorJson(ApiResponseMessages.ModelBindingError);
        }
        private void AdminRoleManageUpdate(AdminRoleModel model)
        {
            if (model.Id <= 0 || string.IsNullOrEmpty(model.RoleName))
                throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
            if (model.RoleName.Length > 100)
                throw new NowaException(string.Format(ApiResponseMessages.MaxLimit, "角色名称", 100));
            var organize = _systemdatadicService.GetDataDicTreeById(model.FKOrganizeId);
            if (organize == null || organize.GroupType != EntityEnumConfig.DataDicGroup.Oragnize || organize.IsActive == EntityEnumConfig.YesorNo.No)
                throw new NowaException(ApiResponseMessages.OrganizeNotExists);
            var roleEntity = model.ToEntity<AdminRole>();
            IList<string> exclude = new List<string>();
            exclude.Add(roleEntity.nameof(r => r.CreatedOnTimeUtc));
            roleEntity.SysLogLvl = Core.Configuration.SystemLogLevel.Information;
            roleEntity.SysLogMsg = string.Format("角色Id：{0} 修改操作，操作人：{1}", roleEntity.Id, _workContext.CurrentAdminUser.UserName);
            _adminuserService.UpdateAdminRole(roleEntity, exclude);
        }
        private void CreateAdminRole(AdminRoleModel model)
        {
            if (string.IsNullOrEmpty(model.RoleName))
                throw new NowaException(ApiResponseMessages.ArgumentCannotBeNull);
            if (model.RoleName.Length > 100)
                throw new NowaException(string.Format(ApiResponseMessages.MaxLimit, "角色名称", 100));
            var organize = _systemdatadicService.GetDataDicTreeById(model.FKOrganizeId);
            if (organize == null || organize.GroupType != EntityEnumConfig.DataDicGroup.Oragnize || organize.IsActive == EntityEnumConfig.YesorNo.No)
                throw new NowaException(ApiResponseMessages.OrganizeNotExists);
            var roleEntity = model.ToEntity<AdminRole>();
            roleEntity.CreatedOnTimeUtc = DateTime.UtcNow;
            _adminuserService.InsertAdminRole(roleEntity);
        }
        [HttpDelete(BackendApiRouteConfig.DeleteAdminRole)]
        public async Task<IActionResult> DeleteAdminRole([FromBody]DeleteNodeModel node)
        {
            try
            {
                if (!ModelState.IsValid || node == null) throw new NowaException(ApiResponseMessages.ModelBindingError);
                if (!_permissionService.AuthorizeModuleButton(node.ModuleId, node.ButtonId))
                    throw new NowaException(ApiResponseMessages.PermissionNotAuthorize);
                if (_adminuserService.CheckAdminRoleBeforeDelete(node.EntityId))
                    throw new NowaException(ApiResponseMessages.UserHasOnlyOneRole);
                var deleteNode = _adminuserService.GetAdminRoleById(node.EntityId);
                if (deleteNode == null || deleteNode.IsActive == EntityEnumConfig.YesorNo.No)
                    throw new NowaException(ApiResponseMessages.EntityNotFound);
                if (deleteNode.IsAdmin == EntityEnumConfig.YesorNo.YES)
                    throw new NowaException(ApiResponseMessages.SystemAdminRoleCannotDelete);

                deleteNode.RoleName = deleteNode.RoleName + "-Deleted";
                deleteNode.IsActive = EntityEnumConfig.YesorNo.No;
                deleteNode.SysLogLvl = Core.Configuration.SystemLogLevel.Information;
                deleteNode.SysLogMsg = string.Format("角色Id：{0}被删除，操作人：{1}", deleteNode.Id, _workContext.CurrentAdminUser.UserName);
                IList<string> exclude = new List<string>();
                exclude.Add(deleteNode.nameof(r => r.CreatedOnTimeUtc));
                _adminuserService.UpdateAdminRole(deleteNode, exclude);

                return SuccessJson(ApiResponseMessages.UpdateSuccessAndRefreshCache);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
    }
}
